License - CS50x 2023
学习目标
- 练习使用文件和文件指针
- 进一步练习字符串和数组
- 使用
debug50
进行调试 - 使用
valgrind
检查内存泄漏
背景
假设你在一家开发人工智能车牌识别技术的公司工作。在开发你的技术时,你可能想使用实际的车牌号码作为测试数据。你有一个包含一些车牌号码的文本文件,你想对其进行分析,所以你首先尝试从该文本文件中读取并打印出车牌,以测试你的文件读取逻辑。但是当你运行你的程序时,只有最后一个号码被打印了 8 次!哪里出错了?
演示
开始
- 使用你的 GitHub 帐户登录 cs50.dev。
- 单击终端窗口内部并执行
cd
。 - 执行
wget https://cdn.cs50.net/2022/fall/labs/4/license.zip
,然后按 Enter 键,以便在你的 codespace 中下载一个名为license.zip
的 zip 文件。请注意wget
命令后URL之间的空格,以及其他任何字符错误! - 现在执行
unzip license.zip
以创建一个名为license
的文件夹。 - 你不再需要 ZIP 文件,因此你可以执行
rm license.zip
并在提示符下回复“y”,然后按 Enter 键。
实现细节
如果你打开 plates.txt
文件,你会注意到实际上有 8 个不同的车牌号码。分发代码中存在一些错误,导致这种情况发生。让我们首先浏览一下代码。
我们首先检查命令行参数,因为 argv[1]
应该是包含车牌的文本文件。然后我们创建一个长度为 7 的字符数组,因为车牌号码是 6 个 char
,我们需要为 NUL 终止符保存空间。现在我们创建一个 char *
数组(字符指针,也称为 string
),以存储 8 个车牌号码。我们创建一个指向外部文本文件的文件指针,创建一个变量来保存每个数组元素的索引,然后开始读取文件并将车牌号码保存到数组中。最后,为了测试我们是否正确地完成了此操作,我们打印出数组中的值。
但是,当我们编译并执行此代码时,显然有些问题。你需要进行适当的更正!
调试
仔细检查实际添加到数组中的数值。你可以使用 debug50
来查找分发代码中的错误。
提示
- 变量
buffer
中到底存储了什么内容,以至于它被赋给了plates
数组的每一个元素? - 请注意,
plates
数组是一个char *
数组或字符串指针数组。 - 那么,将字符数组
buffer
赋值给char *
时,究竟发生了什么?
- 变量
有没有更好的方法将车牌号码复制到 license
数组?
更多提示
strcpy
在这里适用吗?- 如果将数据复制到指针,数据将去哪里?
- 这里需要
malloc
吗?
检查内存泄漏
当你的程序运行正常后,请使用valgrind检查是否存在内存泄漏。
valgrind ./license plates.txt
你可能会得到类似这样的结果:
==24478== 堆内存摘要:
==24478== 程序退出时正在使用:528 字节,共 9 个块
==24478== 堆总计:分配 10 次,释放 1 次,共 4,624 字节
==24478==
==24478== 在第一条丢失记录中,确认有 56 字节分散在 8 个内存块中丢失
==24478== 位于 0x4848899:malloc (位于 /usr/libexec/valgrind/vgpreload_memcheck-amd64-linux.so)
==24478== 位于 0x109207:main (license.c:30)
==24478==
==24478== 在第二条丢失记录中,有 472 字节分散在 1 个内存块中仍然可访问
==24478== 位于 0x4848899:malloc (位于 /usr/libexec/valgrind/vgpreload_memcheck-amd64-linux.so)
==24478== 位于 0x4A086CD:__fopen_internal (iofopen.c:65)
==24478== 位于 0x4A086CD:fopen@@GLIBC_2.2.5 (iofopen.c:86)
==24478== 位于 0x1091CD:main (license.c:20)
==24478==
==24478== 内存泄漏摘要:
==24478== 确认丢失:56 字节,分散在 8 个内存块中
==24478== 间接丢失:0 字节,分散在 0 个内存块中
==24478== 可能丢失:0 字节,分散在 0 个内存块中
==24478== 仍然可访问:472 字节,分散在 1 个内存块中
==24478== 已忽略:0 字节,共 0 个块
==24478==
==24478== 要查看检测到的和被忽略的错误列表,请使用 -s 参数重新运行
==24478== 错误摘要:1 个错误,来自 1 个上下文(已忽略:0 个,来自 0 个上下文)
这里似乎存在两种需要解决的内存错误!
提示
- 您的行号可能不同,但请注意,第 30 行的
main
函数中似乎存在内存问题(与malloc
有关?),以及第 20 行(与fopen
相关的问题?)。分发代码可能缺少什么?
- 您的行号可能不同,但请注意,第 30 行的
如何测试你的代码
你的程序应该产生如下示例所示的结果。
license/ $ ./license plates.txt
11ZT00
1KAD21
78ZZ01
99ZZ11
72ZZ21
98ZZ31
44ZW41
34ZZ51
你可以使用 check50
检查你的代码,check50
是 CS50 在你提交时用来测试你的代码的程序,通过在 $
提示符下输入以下内容。但一定要自己测试一下!
check50 cs50/labs/2023/x/license
要评估你的代码风格,请在 $
提示符下输入以下内容。
如何提交
无需提交!这是一个练习题。